package com.cloudinnov.aop;

import java.lang.reflect.Method;
import java.util.Enumeration;
import java.util.HashMap;
import java.util.Map;

import javax.servlet.http.HttpServletRequest;

import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.AfterThrowing;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import com.cloudinnov.logic.SysLogsLogic;
import com.cloudinnov.model.SysLogs;
import com.cloudinnov.utils.CommonUtils;
import com.cloudinnov.utils.PropertiesUtils;

import redis.clients.jedis.Jedis;
import redis.clients.jedis.JedisPool;

/**
 * @author chengning
 * @date 2016年2月18日下午10:27:40
 * @email ningcheng@cloudinnov.com
 * @remark 记录操作日志。在任何方法前面加systemlog注解，则该方法使用的时候会把使用情况记录到systemlgo表中
 * @version
 */
@Aspect
@Component
public class LogAopAction {
	private static final Logger logger = LoggerFactory.getLogger(LogAopAction.class);
	@Autowired
	private SysLogsLogic sysLogsLogic;
	@Autowired
	private JedisPool redisPool;
	@Autowired
	private HttpServletRequest request;

	// Controller层切点
	@Pointcut("@annotation(com.cloudinnov.aop.SystemLog)")
	public void controllerAspect() {
	}
	/**
	 * 操作异常记录
	 * @descript
	 * @param point
	 * @param e
	 * @author LJN
	 * @date 2015年5月5日
	 * @version 1.0
	 */
	@AfterThrowing(pointcut = "controllerAspect()", throwing = "e")
	public void doAfterThrowing(JoinPoint point, Throwable e) {
		String user = null;
		String ip = null;
		Map<String, Object> map = null;
		try {
			ip = CommonUtils.toIpAddr(request);
		} catch (Exception ee) {
			ip = "无法获取登录用户Ip";
		}
		try {
			map = getControllerMethodDescription(point);
			// 登录名
			user = CommonUtils.findUserSessionId(request).toString();
			if (CommonUtils.isEmpty(user)) {
				user = "无法获取登录用户信息！";
			}
		} catch (Exception ee) {
			user = "无法获取登录用户信息！";
		}
		Jedis redis = null;
		SysLogs sysLogs = new SysLogs();
		try {
			redis = redisPool.getResource();
			redis.select(Integer.parseInt(PropertiesUtils.findPropertiesKey("redis.db.login")));
			String token = request.getParameter("token");
			sysLogs.setUserip(ip);
			sysLogs.setModule(String.valueOf(map.get("module")));
			sysLogs.setDescription(String.valueOf(map.get("description")));
			sysLogs.setMethods(String.valueOf(map.get("methods")));
			sysLogs.setCode(CommonUtils.getUUID());
			String oemCode = redis.get("login:" + token + ":oemCode");
			String userCode = redis.get("login:" + token + ":code");
			String userName = redis.get("login:" + token + ":loginName");
			sysLogs.setOemCode(oemCode);
			sysLogs.setUserCode(userCode);
			sysLogs.setLoginName(userName);
		} catch (Exception e1) {
			e1.printStackTrace();
		} finally {
			sysLogs.setStatus(CommonUtils.STATUS_EXCEPTION);
			sysLogsLogic.save(sysLogs);
			redisPool.returnResource(redis);
		}
	}
	/**
	 * 前置通知 用于拦截Controller层记录用户的操作
	 * @param joinPoint 切点
	 */
	@Around("controllerAspect()")
	public Object doController(ProceedingJoinPoint point) {
		Object result = null;
		// 执行方法名
		String methodName = point.getSignature().getName();
		String className = point.getTarget().getClass().getSimpleName();
		Map<String, Object> map = null;
		Long start = 0L;
		Long end = 0L;
		Long time = 0L;
		String ip = null;
		try {
			ip = CommonUtils.toIpAddr(request);
		} catch (Exception e) {
			ip = "无法获取登录用户Ip";
		}
		// 当前用户
		try {
			map = getControllerMethodDescription(point);
			// 执行方法所消耗的时间
			start = System.currentTimeMillis();
			result = point.proceed();
			end = System.currentTimeMillis();
			time = end - start;
			logger.debug("执行方法消耗时间:" + time);
		} catch (Throwable e) {
			throw new RuntimeException(e);
		}
		Jedis redis = null;
		try {
			redis = redisPool.getResource();
			redis.select(Integer.parseInt(PropertiesUtils.findPropertiesKey("redis.db.login")));
			SysLogs sysLogs = new SysLogs();
			String token = request.getParameter("token");
			sysLogs.setUserip(ip);
			sysLogs.setModule(String.valueOf(map.get("module")));
			sysLogs.setDescription(String.valueOf(map.get("description")));
			sysLogs.setMethods(String.valueOf(map.get("methods")));
			sysLogs.setCode(CommonUtils.getUUID());
			String oemCode = redis.get("login:" + token + ":oemCode");
			String userCode = redis.get("login:" + token + ":code");
			String userName = redis.get("login:" + token + ":loginName");
			sysLogs.setOemCode(oemCode);
			sysLogs.setUserCode(userCode);
			sysLogs.setLoginName(userName);
			sysLogs.setActiontime(time.toString());
			sysLogs.setStatus(CommonUtils.STATUS_NORMAL);
			sysLogsLogic.save(sysLogs);
			logger.debug("=====通知开始=====");
			logger.debug("请求方法:" + className + "." + methodName + "()");
			logger.debug("方法描述:" + map);
			logger.debug("请求IP:" + ip);
			logger.debug("=====通知结束=====");
		} catch (Exception e) {
			// 记录本地异常日志
			logger.error("====通知异常====");
			logger.error("异常信息:{}", e);
		} finally {
			redisPool.returnResource(redis);
		}
		return result;
	}
	/**
	 * 获取注解中对方法的描述信息 用于Controller层注解
	 * @param joinPoint 切点
	 * @return 方法描述
	 * @throws Exception
	 */
	@SuppressWarnings("rawtypes")
	public Map<String, Object> getControllerMethodDescription(JoinPoint joinPoint) throws Exception {
		Map<String, Object> map = new HashMap<String, Object>();
		String targetName = joinPoint.getTarget().getClass().getName();
		String methodName = joinPoint.getSignature().getName();
		logger.debug("类名称" + targetName);
		logger.debug("方法名称" + methodName);
		Object[] arguments = joinPoint.getArgs();
		Class targetClass = Class.forName(targetName);
		Method[] methods = targetClass.getMethods();
		for (Method method : methods) {
			if (method.getName().equals(methodName)) {
				Class[] clazzs = method.getParameterTypes();
				if (clazzs.length == arguments.length) {
					for (Enumeration<String> argNames = request.getParameterNames(); argNames.hasMoreElements();) {
						String thisName = argNames.nextElement().toString();
						String thisValue = request.getParameter(thisName);
						logger.debug("参数名称:   " + thisName + "  ----参数值:  " + thisValue);
					}
					map.put("module", method.getAnnotation(SystemLog.class).module());
					map.put("methods", method.getAnnotation(SystemLog.class).methods());
					String de = method.getAnnotation(SystemLog.class).description();
					if (CommonUtils.isEmpty(de))
						de = "执行成功";
					map.put("description", de);
					break;
				}
			}
		}
		return map;
	}
}
